home *** CD-ROM | disk | FTP | other *** search
/ AI Game Programming Wisdom / AIGameProgrammingWisdom.iso / SourceCode / 11 Learning / 04 Mommersteeg / Penny / PennyMatchingDlg.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-09-25  |  11.3 KB  |  402 lines

  1. // PennyMatchingDlg.cpp : implementation file
  2. //
  3.  
  4. #include "stdafx.h"
  5. #include "PennyMatching.h"
  6. #include "PennyMatchingDlg.h"
  7.  
  8. // include predictors
  9. #include "RandomPredictor.h"
  10. #include "SimplePredictor.h"
  11. #include "StringMatchPredictor.h"
  12. #include "ImprovedPredictor.h"
  13. #include "SelfAdjustingPredictor.h"
  14.  
  15. #ifdef _DEBUG
  16. #define new DEBUG_NEW
  17. #undef THIS_FILE
  18. static char THIS_FILE[] = __FILE__;
  19. #endif
  20.  
  21. #define HEAD 0
  22. #define TAIL 1
  23.  
  24. /////////////////////////////////////////////////////////////////////////////
  25. // CAboutDlg dialog used for App About
  26.  
  27. class CAboutDlg : public CDialog
  28. {
  29. public:
  30.     CAboutDlg();
  31.  
  32. // Dialog Data
  33.     //{{AFX_DATA(CAboutDlg)
  34.     enum { IDD = IDD_ABOUTBOX };
  35.     CString    m_BackgroundInfo;
  36.     //}}AFX_DATA
  37.  
  38.     // ClassWizard generated virtual function overrides
  39.     //{{AFX_VIRTUAL(CAboutDlg)
  40.     protected:
  41.     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
  42.     //}}AFX_VIRTUAL
  43.  
  44. // Implementation
  45. protected:
  46.     //{{AFX_MSG(CAboutDlg)
  47.     afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
  48.     //}}AFX_MSG
  49.     DECLARE_MESSAGE_MAP()
  50. };
  51.  
  52. CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
  53. {
  54.     //{{AFX_DATA_INIT(CAboutDlg)
  55.     m_BackgroundInfo = _T("");
  56.     //}}AFX_DATA_INIT
  57. }
  58.  
  59. void CAboutDlg::DoDataExchange(CDataExchange* pDX)
  60. {
  61.     CDialog::DoDataExchange(pDX);
  62.     //{{AFX_DATA_MAP(CAboutDlg)
  63.     DDX_Text(pDX, IDC_BACKGROUND_INFO, m_BackgroundInfo);
  64.     //}}AFX_DATA_MAP
  65. }
  66.  
  67. BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
  68.     //{{AFX_MSG_MAP(CAboutDlg)
  69.     ON_WM_CREATE()
  70.     //}}AFX_MSG_MAP
  71. END_MESSAGE_MAP()
  72.  
  73. /////////////////////////////////////////////////////////////////////////////
  74. // CPennyMatchingDlg dialog
  75.  
  76. CPennyMatchingDlg::CPennyMatchingDlg(CWnd* pParent /*=NULL*/)
  77.     : CDialog(CPennyMatchingDlg::IDD, pParent)
  78. {
  79.     //{{AFX_DATA_INIT(CPennyMatchingDlg)
  80.     m_MachineScore = _T("");
  81.     m_NumberOfPlays = _T("");
  82.     m_SuccessRatio = _T("");
  83.     m_YourScore = _T("");
  84.     m_ThresholdRatio = _T("");
  85.     //}}AFX_DATA_INIT
  86.     // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
  87.     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  88. }
  89.  
  90. void CPennyMatchingDlg::DoDataExchange(CDataExchange* pDX)
  91. {
  92.     CDialog::DoDataExchange(pDX);
  93.     //{{AFX_DATA_MAP(CPennyMatchingDlg)
  94.     DDX_Control(pDX, IDC_TAIL, m_Tail);
  95.     DDX_Control(pDX, IDC_HEAD, m_Head);
  96.     DDX_Control(pDX, IDC_TOGGLESTATS, m_ToggleStatistics);
  97.     DDX_Control(pDX, IDC_PREDICTOR, m_Predictors);
  98.     DDX_Text(pDX, IDC_MACHINE_SCORE, m_MachineScore);
  99.     DDX_Text(pDX, IDC_PLAYS, m_NumberOfPlays);
  100.     DDX_Text(pDX, IDC_RATIO, m_SuccessRatio);
  101.     DDX_Text(pDX, IDC_YOUR_SCORE, m_YourScore);
  102.     DDX_Text(pDX, IDC_THRESHOLDRATIO, m_ThresholdRatio);
  103.     //}}AFX_DATA_MAP
  104. }
  105.  
  106. BEGIN_MESSAGE_MAP(CPennyMatchingDlg, CDialog)
  107.     //{{AFX_MSG_MAP(CPennyMatchingDlg)
  108.     ON_WM_SYSCOMMAND()
  109.     ON_WM_PAINT()
  110.     ON_WM_QUERYDRAGICON()
  111.     ON_WM_CREATE()
  112.     ON_CBN_SELCHANGE(IDC_PREDICTOR, OnSelChangePredictor)
  113.     ON_WM_DESTROY()
  114.     ON_BN_CLICKED(IDC_HEAD, OnHead)
  115.     ON_BN_CLICKED(IDC_TAIL, OnTail)
  116.     ON_BN_CLICKED(IDC_TOGGLESTATS, OnToggleStats)
  117.     ON_BN_CLICKED(IDC_ABOUT, OnAbout)
  118.     //}}AFX_MSG_MAP
  119. END_MESSAGE_MAP()
  120.  
  121. /////////////////////////////////////////////////////////////////////////////
  122. // CPennyMatchingDlg message handlers
  123.  
  124. BOOL CPennyMatchingDlg::OnInitDialog()
  125. {
  126.     CDialog::OnInitDialog();
  127.  
  128.     // Add "About..." menu item to system menu.
  129.  
  130.     // IDM_ABOUTBOX must be in the system command range.
  131.     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  132.     ASSERT(IDM_ABOUTBOX < 0xF000);
  133.  
  134.     CMenu* pSysMenu = GetSystemMenu(FALSE);
  135.     if (pSysMenu != NULL)
  136.     {
  137.         CString strAboutMenu;
  138.         strAboutMenu.LoadString(IDS_ABOUTBOX);
  139.         if (!strAboutMenu.IsEmpty())
  140.         {
  141.             pSysMenu->AppendMenu(MF_SEPARATOR);
  142.             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  143.         }
  144.     }
  145.  
  146.     // Set the icon for this dialog.  The framework does this automatically
  147.     //  when the application's main window is not a dialog
  148.     SetIcon(m_hIcon, TRUE);            // Set big icon
  149.     SetIcon(m_hIcon, FALSE);        // Set small icon
  150.     
  151.     // add random predictor
  152.     CRandomPredictor * pRandomPredictor = new CRandomPredictor;
  153.     pRandomPredictor->Setup(2, GetTickCount());
  154.     RegisterPredictor("Random predictor (bad performance)", pRandomPredictor);
  155.  
  156.     // add simple string-matching predictor
  157.     CSimplePredictor * pSimplePredictor = new CSimplePredictor;
  158.     pSimplePredictor->Setup(1000, 5);
  159.     RegisterPredictor("O(N^2) String matching predictor (good performance but slow)", pSimplePredictor);
  160.  
  161.     // add efficient string-matching predictor
  162.     CStringMatchPredictor * pStringMatchPredictor = new CStringMatchPredictor;
  163.     pStringMatchPredictor->Setup(1000, 2, 5);
  164.     RegisterPredictor("O(N) String matching predictor (good performance and fast)", pStringMatchPredictor);
  165.  
  166.     // add improved string-matching predictor
  167.     CImprovedPredictor * pImprovedPredictor = new CImprovedPredictor;
  168.     pImprovedPredictor->Setup(1000, 2, 0.6f);
  169.     RegisterPredictor("Improved O(N) String matching predictor (best performance and fast)", pImprovedPredictor);
  170.  
  171.     // add improved string-matching predictor
  172.     CSelfAdjustingPredictor * pSelfAdjustingPredictor = new CSelfAdjustingPredictor;
  173.     pSelfAdjustingPredictor->Setup(1000, 2, 0.6f);
  174.     RegisterPredictor("Self adjusting O(N) String matching predictor", pSelfAdjustingPredictor);
  175.  
  176.     /*HICON hIcon;
  177.     hIcon = ::LoadIcon(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_HEAD));
  178.     m_Head.SetIcon( hIcon );
  179.     hIcon = ::LoadIcon(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_TAIL));
  180.     m_Tail.SetIcon( hIcon );*/
  181.  
  182.     //m_Head.AutoLoad(IDB_HEAD, this); //LoadBitmaps(MAKEINTRESOURCE(IDB_HEAD));
  183.     //m_Tail.AutoLoad(IDB_TAIL, this);
  184.  
  185.     m_hBitmapHead = ::LoadBitmap(AfxGetResourceHandle(), MAKEINTRESOURCE(IDB_HEAD)); 
  186.     m_Head.SendMessage(BM_SETIMAGE, IMAGE_BITMAP, (long)m_hBitmapHead);
  187.  
  188.     m_hBitmapTail = ::LoadBitmap(AfxGetResourceHandle(), MAKEINTRESOURCE(IDB_TAIL)); 
  189.     m_Tail.SendMessage(BM_SETIMAGE, IMAGE_BITMAP, (long)m_hBitmapTail);
  190.  
  191.  
  192. /*
  193. Specifies that the button displays a bitmap (BS_BITMAP) instead of text.Type: Bool. Default:
  194.  False. 
  195. The BS_BITMAP is a new button style in Windows 95.  After a button is created with this 
  196. style, assign the bitmap to the button by sending a BM_SETIMAGE message to the button with
  197.  the wParam as IMAGE_BITMAP and lParam as a handle to the bitmap. Windows displays the 
  198.  specified bitmap on the button.  The attached bitmap should not be deleted until the button
  199.  is destroyed. 
  200. */
  201.  
  202.     m_bExpanded = true;
  203.     OnToggleStats();
  204.     ResetGame();    
  205.  
  206.     return TRUE;  // return TRUE  unless you set the focus to a control
  207. }
  208.  
  209. void CPennyMatchingDlg::OnSysCommand(UINT nID, LPARAM lParam)
  210. {
  211.     if ((nID & 0xFFF0) == IDM_ABOUTBOX)
  212.     {
  213.         CAboutDlg dlgAbout;
  214.         dlgAbout.DoModal();
  215.     }
  216.     else
  217.     {
  218.         CDialog::OnSysCommand(nID, lParam);
  219.     }
  220. }
  221.  
  222. // If you add a minimize button to your dialog, you will need the code below
  223. //  to draw the icon.  For MFC applications using the document/view model,
  224. //  this is automatically done for you by the framework.
  225.  
  226. void CPennyMatchingDlg::OnPaint() 
  227. {
  228.     if (IsIconic())
  229.     {
  230.         CPaintDC dc(this); // device context for painting
  231.  
  232.         SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
  233.  
  234.         // Center icon in client rectangle
  235.         int cxIcon = GetSystemMetrics(SM_CXICON);
  236.         int cyIcon = GetSystemMetrics(SM_CYICON);
  237.         CRect rect;
  238.         GetClientRect(&rect);
  239.         int x = (rect.Width() - cxIcon + 1) / 2;
  240.         int y = (rect.Height() - cyIcon + 1) / 2;
  241.  
  242.         // Draw the icon
  243.         dc.DrawIcon(x, y, m_hIcon);
  244.     }
  245.     else
  246.     {
  247.         CDialog::OnPaint();
  248.     }
  249. }
  250.  
  251. // The system calls this to obtain the cursor to display while the user drags
  252. //  the minimized window.
  253. HCURSOR CPennyMatchingDlg::OnQueryDragIcon()
  254. {
  255.     return (HCURSOR) m_hIcon;
  256. }
  257.  
  258. int CPennyMatchingDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  259. {
  260.     if (CDialog::OnCreate(lpCreateStruct) == -1)
  261.         return -1;
  262.  
  263.     return 0;
  264. }
  265.  
  266. void CPennyMatchingDlg::OnSelChangePredictor() 
  267. {
  268.     ResetGame();
  269. }
  270.  
  271. void CPennyMatchingDlg::RegisterPredictor(const CString &PredictorName, CPredictor *pPredictor)
  272. {
  273.     int nIndex = m_Predictors.AddString(PredictorName);
  274.     m_Predictors.SetItemData(nIndex, (DWORD)pPredictor);
  275.     m_Predictors.SetCurSel(nIndex);
  276. }
  277.  
  278. void CPennyMatchingDlg::OnDestroy() 
  279. {
  280.     CDialog::OnDestroy();
  281.     
  282.     // release memory occupied by the predictors
  283.     for (int i = 0; i<m_Predictors.GetCount(); i++) {
  284.         CPredictor * pPredictor = (CPredictor *)m_Predictors.GetItemData(i);
  285.         delete pPredictor;
  286.     }
  287. }
  288.  
  289. void CPennyMatchingDlg::ResetGame()
  290. {
  291.     int nIndex = m_Predictors.GetCurSel();
  292.     m_pPredictor = (CPredictor *)m_Predictors.GetItemData(nIndex);
  293.  
  294.     m_nPlays = 0;
  295.     m_nMachineWins = 0;
  296.     m_nPlayerWins = 0;
  297.     m_nTotalPredictions = 0;
  298.     m_nSuccessfulPredictions = 0;
  299.  
  300.     UpdateDisplay();
  301. }
  302.  
  303. void CPennyMatchingDlg::UpdateDisplay()
  304. {
  305.     m_MachineScore.Format("%d", m_nMachineWins);
  306.     m_YourScore.Format("%d", m_nPlayerWins);
  307.  
  308.     if (m_nPlays > 0) {
  309.         m_SuccessRatio.Format("%d%%", (100 * m_nMachineWins) / m_nPlays);
  310.     } else {
  311.         m_SuccessRatio = "N/A";
  312.     }
  313.  
  314.     if (m_nTotalPredictions > 0) {
  315.         m_ThresholdRatio.Format("%d%%", (100 * m_nSuccessfulPredictions) / m_nTotalPredictions);
  316.     } else {
  317.         m_ThresholdRatio = "N/A";
  318.     }
  319.  
  320.     m_NumberOfPlays.Format("%d", m_nPlays);
  321.  
  322.     UpdateData(FALSE);
  323. }
  324.  
  325. void CPennyMatchingDlg::OnHead() 
  326. {
  327.     ProcessSelection(HEAD);
  328. }
  329.  
  330. void CPennyMatchingDlg::OnTail() 
  331. {
  332.     ProcessSelection(TAIL);
  333. }
  334.  
  335. void CPennyMatchingDlg::ProcessSelection(int Selection) {
  336.     int Prediction;
  337.  
  338.     if (m_pPredictor->GetPrediction(Prediction)) {
  339.         m_nTotalPredictions++;
  340.         if (Prediction==Selection) {
  341.             m_nSuccessfulPredictions++;
  342.         }
  343.     }
  344.  
  345.     if (Prediction==Selection) {
  346.         m_nMachineWins++;    
  347.     } else {
  348.         m_nPlayerWins++;
  349.     }
  350.  
  351.     m_nPlays++;
  352.     m_pPredictor->Update(Selection);
  353.     UpdateDisplay();
  354. }
  355.  
  356. void CPennyMatchingDlg::OnToggleStats() 
  357. {
  358.     CRect rcDialog;
  359.     int nNewHeight;
  360.     GetWindowRect( &rcDialog );
  361.  
  362.     if (m_bExpanded) {
  363.         nNewHeight = rcDialog.Height() / 2;
  364.         m_ToggleStatistics.SetWindowText("Show &statistics >>");
  365.  
  366.     } else {
  367.         nNewHeight = rcDialog.Height() * 2;
  368.         m_ToggleStatistics.SetWindowText("Hide &statistics <<");
  369.     }
  370.  
  371.     SetWindowPos(NULL, 0, 0, rcDialog.Width(), nNewHeight, SWP_NOMOVE | SWP_NOZORDER );
  372.  
  373.     /*
  374.     CWnd * pWndControl = GetWindow( GW_CHILD );
  375.     while ( pWndControl != NULL) {
  376.         CRect rcControl;
  377.         pWndControl->GetWindowRect( &rcControl );
  378.         pWndControl->EnableWindow( rcControl.top <= rcDialog.top + nNewHeight;
  379.         pWndControl = pWndControl->GetWindow( GW_HWNDNEXT );
  380.     }
  381.     */
  382.  
  383.     m_bExpanded = !m_bExpanded;
  384. }
  385.  
  386. int CAboutDlg::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  387. {
  388.     if (CDialog::OnCreate(lpCreateStruct) == -1)
  389.         return -1;
  390.     
  391.     // TODO: Add your specialized creation code here
  392.     m_BackgroundInfo = "'At Bell Laboratories David Hagelbarger built a simple mind-reading machine, whose purpose\r\r\nwas to play the \"penny matching\" game. In this game, a player chooses head or tail, while\r\na mind-reading machine tries to predict and match his/her choice.\r\n\r\nHagelbargers simple 8-state machine was able to match the \"pennies\" of its human\r\nopponent 5218 times over a course of 9795 plays. Hagelbarger's machine recorded and \r\nanalyzed its human opponent's past choices, looking for patterns that would foretell the\r\nnext choice; since it is almost impossible for a human to avoid falling into such patterns,\r\nHagelbarger's machine could be successful in more than 50% of the time.'";
  393.     
  394.     return 0;
  395. }
  396.  
  397. void CPennyMatchingDlg::OnAbout() 
  398. {
  399.     CAboutDlg dlg;
  400.     dlg.DoModal();
  401. }
  402.